﻿/* Muaz Khan – http://dashingquill.web.officelive.com */

using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Linq;
using System.Collections.Generic;
using DTweet.Models;

namespace DTweet.Helpers
{
    /***********************************
    * Extension methods commonly used in the Views or in Controllers
    ***********************************/
    public static class CommonExtensions
    {
        public static string Truncate(this string text, int maxLength, bool insertDots = true)
        {
            if (string.IsNullOrEmpty(text) || maxLength <= 0)
                return string.Empty;
            return text.Length > maxLength ? text.Substring(0, maxLength) + (insertDots ? "..." : "") : text;
        }

        public static string[] SplitString(this string original)
        {
            if (string.IsNullOrEmpty(original)) return new string[0];

            return (original.Split(new[] {' '}).Select(piece => new {piece, trimmed = piece.Trim()}).Where(
                @t => !string.IsNullOrEmpty(@t.trimmed)).Select(@t => @t.trimmed)).ToArray();
        }

        /***********************************
         * validate the tweet-message
         ***********************************/
        public static string Validate(this string value)
        {
            return value
                .Replace("--", " ")
                .Replace("-qmark", "?")
                .Replace("-n", " <br />")
                .Replace("-lt", "&lt;")
                .Replace("-gt", "&gt;")
                .Replace("-amp", "&amp;")
                .Replace("-nsign", "#")
                .Replace("__", "-");
        }

        /***********************************
         *  <meta name="description" content="@tweet.Message.GenerateDescription()" /> --- Status.cshtml
         ***********************************/
        public static string GenerateDescription(this string text)
        {
            return text/*.ToLower()*/.Truncate(145, false).ResolveForTitleAndDescription().RemoveUnnecessaryStuff();
        }

        public static bool IsEmail(this string email)
        {
            return new Regex(@"\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*").IsMatch(email);
        }

        public static int ToInt(this string input)
        {
            int integer;
            int.TryParse(input, out integer);
            return integer;
        }

        public static string FormateLines(this string stringToFormat)
        {
            var sb = new StringBuilder();
            var sr = new StringReader(stringToFormat);
            string buffer;
            do
            {
                buffer = sr.ReadLine();
                if (buffer != null)
                {
                    sb.Append(buffer);
                    sb.Append("<br />");
                }
            } while (buffer != null);

            return sb.ToString();
        }

        public static bool HasHtml(this string input)
        {
            return input.Contains("<") || input.Contains(">");
        }

        /***********************************
         * Using deprecated <time> element
         ***********************************/
        public  static string ToMachineTime(this System.DateTime dateToConvert)
        {
            // getting machine-friendly format - <time datetime="2011-09-15T08:33PM">Sep 15, 2011 - 08:33 PM</time>
            var year = dateToConvert.Year.ToString();
            var month = dateToConvert.Month.ToString();
            if (month.Length == 1) month = "0" + month;

            var day = dateToConvert.Day.ToString();
            if (day.Length == 1) day = "0" + day;
            var time = dateToConvert.ToLongTimeString();
            if (dateToConvert.Hour.ToString().Length == 1)
                time = "0" + time;

            return year + "/" + month + "/" + day + "T" + time;
        }

        #region ID Converter

        /***********************************
         * Helpful setting cookies names + values [for security purpose!]
         ***********************************/
        public static string ToNumbers(this string numbers)
        {
            return numbers
                .Replace("xG", "1")
                .Replace("kaH", "2")
                .Replace("Qb", "3")
                .Replace("ldC", "4")
                .Replace("Wew", "5")
                .Replace("Lpv", "6")
                .Replace("scD", "7")
                .Replace("rBq", "8")
                .Replace("htA", "9")
                .Replace("yXg", "0");
        }

        public static string ToText(this int numbers)
        {
            return numbers.ToString().ToText();
        }

        public static string ToText(this string numbers)
        {
            return numbers
                .Replace("1", "xG")
                .Replace("2", "kaH")
                .Replace("3", "Qb")
                .Replace("4", "ldC")
                .Replace("5", "Wew")
                .Replace("6", "Lpv")
                .Replace("7", "scD")
                .Replace("8", "rBq")
                .Replace("9", "htA")
                .Replace("0", "yXg");
        }

        #endregion

        /***********************************
         * Removing auto-inserted line-break
         ***********************************/
        public static string HandlePreLineBreak(this string text)
        {
            return text.Replace("<pre><br />", "<pre>").Replace("<br /></pre>", "</pre>")                
                .ResolveLinks();
        }

        /***********************************
         * Enabling wiki-markup in the tweet messages
         * http://dashingquill.web.officelive.com/Blogs/2011/Wiki-Markup-Parsing-in-CSharp-An-Implementation.html
         ***********************************/
        public static string ReplaceAll(this string inputString)
        {
            inputString = inputString.Replace("*", "-b-");
            return inputString.Replace(
                new[] { "-b-", "_", "t-", "code-" },
                new[] { "-b-", "_", "-t", "-code" },
                new[] { "<b>", "<i>", "<h2 class=\"tweet-title\">", "<pre>" },
                new[] { "</b>", "</i>", "</h2>", "</pre>" });
        }

        /***********************************
         * Each word must not be too long         
         ***********************************/
        public static string SpecifyWordLength(this string text)
        {
            var splitted = text.Split(' ');
            var result = string.Empty;
            foreach (var s in splitted)
            {
                if (s.Length > 70) result += "<abbr title=\"" + s + "\">" + s.Truncate(70) + "</abbr> ";
                else result += s + " ";
            }
            return result;
        }

        /***********************************
         * @tweet.Message.HandleAllThings()    --- UserPage.cshtml --- Status.cshtml --- HomePage.cshtml
         ***********************************/
        public static string HandleAllThings(this string input)
        {
            input = input.SpecifyWordLength().ReplaceAll().HandlePreLineBreak();
            return input;
        }

        /***********************************
         * Who is following this user: All users who circled him!!
         ***********************************/
        public static CircleInfoHelper GetOtherUsersWhoCircledHim(this DatabaseEntities db, string userToken)
        {
            return GetUsersFromHisCircles(db, userToken, isGetOtherUsersWhoCircledHim: true);
        }

        /***********************************
         * Who is following this user: All users who circled him!!
         ***********************************/
        public static CircleInfoHelper GetUsersFromHisCircles(this DatabaseEntities db, string userToken, bool isGetOtherUsersWhoCircledHim = false)
        {
            var circles = db.Circles.Where(c => c.UserToken == userToken);
            string followingOrFollowers = "Not following anyone!";
            
            if (isGetOtherUsersWhoCircledHim)
            {
                circles = db.Circles.Where(c => c.UserToken != userToken && c.MembersCount > 0 && c.Members.Contains(userToken));
                followingOrFollowers = "Not followed by anyone!";
            }

            var membersCount = 0;
            var members = string.Empty;
            if (circles.Count() > 0)
            {
                foreach (var circle in circles)
                {
                    if (!isGetOtherUsersWhoCircledHim && circle.MembersCount > 0)
                    {
                        members += circle.Members + ","; /* Getting all users from his circles */
                    }
                    else if (isGetOtherUsersWhoCircledHim)
                    {
                        members += circle.UserToken + ","; /* Getting all users who circled him */
                    }
                }
            }
            else members = followingOrFollowers;

            if (members != followingOrFollowers)
            {
                if (members.Contains(","))
                {
                    members = members.Substring(0, members.Length - 1);
                    membersCount = members.Split(',').Distinct().Count();
                }
                if (!string.IsNullOrWhiteSpace(members)) members = db.GetCircleMembersNames(members);
                else members = "No members";
            }

            return new CircleInfoHelper { Count = membersCount, Members = members.Truncate(50) };
        }

        /***********************************
         * Enabling wiki-markup in the tweet messages
         * http://dashingquill.web.officelive.com/Blogs/2011/Wiki-Markup-Parsing-in-CSharp-An-Implementation.html
         ***********************************/
        public static string Replace(this string inputString, 
                                        IList<string> startKeywords, /* code-   */
                                        IList<string> endKeywords,   /* -code   */
                                        IList<string> startTag,      /* <pre> */
                                        IList<string> endTag)        /* </pre> */
        {
            if (startKeywords.Count != startTag.Count || startTag.Count != endTag.Count || startKeywords.Count != endKeywords.Count) return null;
            for (var i = 0; i < startKeywords.Count; i++)
            {
                var r = new Regex(startKeywords[i] + "(.*?)" + endKeywords[i]);
                var matches = r.Matches(inputString);
                for (var j = 0; j < matches.Count; j++)
                {
                    inputString = inputString.Replace(matches[j].Groups[0].Value,
                                                      startTag[i] + matches[j].Groups[1].Value.Trim() +
                                                      endTag[i]);
                }
            }
            return inputString;
        }

        /***********************************
         * Making the title or desciption
         ***********************************/
        public static string ResolveForTitleAndDescription(this string input)
        {
            return input.Replace(" <br />", " ").Replace("&lt;", "").Replace("&gt;", "").Replace("&amp;", "&");
        }

        /***********************************
         * Remove unnecessary stuff for title or description
         ***********************************/
        public static string RemoveUnnecessaryStuff(this string input)
        {
            var unwantedList = new[] { "!", ",", "'", "(", ")", "[", "]", "$", "#", ".", "?", "&", "~", "@", "%", "+", "=", "/", ";", ":", "|", "\\" ,
                                       "*", "_", "code-", "-code", "t-", "-t", "\""};

            foreach (var item in unwantedList)
            {
                input = input.Replace(item, "-");
            }

        Back:

            if (input.Contains("--"))
            {
                input = input.Replace("--", "-");
                goto Back;
            }

            return input.Trim();
        }

        /***********************************
        * ViewBag.Title = tweet.Message.FetchTitle();   --- Status.cshtml
        ***********************************/
        public static string FetchTitle(this string tweetMessage)
        {
            /* SEO: A <title> tag not be empty and should contain 65 characters or fewer. */
            tweetMessage = tweetMessage.ResolveForTitleAndDescription();

            var r = new Regex("t-(.*?)-t");
            var matches = r.Matches(tweetMessage);
            if (matches.Count > 0)
            {
                /* It is the user-defined title and I think it is unnecessary to truncate it; what you say? Mr. SEO! Get out; please! */
                return matches[0].Groups[1].Value.Trim();
            }
            return tweetMessage.RemoveUnnecessaryStuff().Replace("-", "").Trim().Truncate(65, false);
        }

        /***********************************
        * <a href="@Url.Content("~/" + tweet.TweetToken + "/" + tweet.Message.FetchPostUrl())" class="p-Link">...</a>   --- UserPage.cshtml --- Homepage.cshtml
        ***********************************/
        public static string FetchPostUrl(this string tweetMessage)
        {
            var postTitle = tweetMessage.FetchTitle();
            var splittedString = postTitle.SplitString();
            postTitle = string.Empty;
            foreach (var s in splittedString)
            {
                postTitle += s + "-";
            }
            postTitle = postTitle.Substring(0, postTitle.Length - 1);
            return postTitle;
        }

        /***********************************
        * Handling wiki-markup for editing the post
        ***********************************/
        public static string ResolveForEdit(this string input)
        {
            return input.Trim().Replace("<br />", "\n")
                .Replace("<h2 class=\"tweet-title\">", "t-")
                .Replace("</h2>", "-t")
                .Replace("<b>", "*")
                .Replace("</b>", "*")
                .Replace("<i>", "_")
                .Replace("</i>", "_")
                .Replace("<pre>", "code-")
                .Replace("</pre>", "-code");
        }

        /***********************************
        * How many times a post is edited
        ***********************************/
        public static string GetEditTimes(this int editCount)
        {
            return editCount == 1 ? "Edited " + editCount + " time" : "Edited " + editCount + " times";
        }
    }
}